package com.marsoft.test.testCompletableFuture;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class testCompletableFuture {

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        // param1 核心线程数，初始化时线程池的个数
        // param2 最大线程数，当任务派发过来时，先使用核心线程处理，核心线程不够时线程进入阻塞队列等待核心线程空闲，
        // 如果阻塞队列也满了，就开启不超过最大线程数的线程帮助处理任务，如果队列满了，线程数也达到了最大线程数，就会采取饱和策略
        // param3，param4 存活时间，即线程数大于核心线程数时，多余线程的存活时间及时间单位
        // param5 阻塞队列
        // param6 线程工厂
        // param7 饱和策略，不指定时默认为AbortPolicy，即抛出异常
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(20, 50, 50, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

        // < -------------------------------------------------- >
        // 启动异步任务
//        runAsync: 没有返回值，不指定线程池默认使用ForkJoinPool
//        supplyAsync:有返回值，不指定线程池默认使用ForkJoinPool
//        CompletableFuture.runAsync(() -> {
//
//            System.out.println(Thread.currentThread().getName());
//
//        }, poolExecutor);

//        // 有返回值
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            int i = 10;
//            System.out.println(Thread.currentThread().getName());
//
//            return i / 0;
//        }, poolExecutor).whenCompleteAsync((res, exception) -> {
//
//            // 计算完成时回调方法
//            // whenComplete使用的时用户线程(在这里就是主线程main)或者是自己指定的线程池中的线程
//            // whenCompleteAsync未指定线程池使用ForkJoinPool线程池，指定了使用自己指定的
//            // whenComplete方法为当上一个任务结束之后的回调函数，whenCompleteAsync表示这个回调函数时异步执行的
//            // 参数res为上边的CompletableFuture处理结果，参数exception为上边的CompletableFuture出现的异常，虽然可以感知异常，但是无法修改返回值
//            System.out.println(Thread.currentThread().getName());
//            System.out.println(res);
//
//        },poolExecutor).exceptionally(throwable -> {
//            System.out.println(Thread.currentThread().getName());
//            // exceptionally：异常发生后的回调函数，可以修改返回结果
//            return 10;
//        });
//
//        Integer integer = future.get();
//        System.out.println(integer);
//
//        // 有返回值
//        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
//            int i = 10;
//            System.out.println(Thread.currentThread().getName());
//
//            return i / 0;
//        }, poolExecutor).handleAsync((res, exception) -> {
//            // handle：类似于whenComplete方法，但是有返回值，即可以在某种情况下改变返回值
//            // handle使用的时用户线程(在这里就是主线程main)或者是自己指定的线程池中的线程
//            // handleAsync未指定线程池使用ForkJoinPool线程池，指定了使用自己指定的
//            System.out.println(Thread.currentThread().getName());
//            // 当有异常时返回0
//            if (exception != null) {
//                res = 0;
//            }
//            return res;
//        });

//        对比 thenApplyAsync和handleAsync的差异：
//        thenApplyAsync是在当前stage正常完成后才会执行，如果有异常抛出则抛出异常不进入。所有以then开始的方法同此原理。
//        handleAsync无论是否异常抛出都会进入，并且返回结果不能够继续抛出异常。使用此方法将会吞噬上一阶段的异常。
        // < -------------------------------------------------- >
//        thenRun使用上一个指定的线程池或者main线程
//        thenRunAsync: 一个CompletableFuture执行完后执行thenRunAsync内的Runnable语句，不能接受上一个
//        Future的返回值，也没有自己的返回值,未指定线程池使用ForkJoinPool线程池，指定了使用自己指定的
//        thenAccept使用上一个指定的线程池或者main线程
//        thenAcceptAsync:一个CompletableFuture执行完后执行thenAcceptAsync内的Runnable语句，能接受上一个
//        Future的返回值，没有自己的返回值,未指定线程池使用ForkJoinPool线程池，指定了使用自己指定的
//        thenApply使用上一个指定的线程池或者main线程
//        thenApplyAsync: 一个CompletableFuture执行完后执行thenApplyAsync内的Runnable语句，能接受上一个
//        Future的返回值，也有自己的返回值,未指定线程池使用ForkJoinPool线程池，指定了使用自己指定的
//        CompletableFuture.supplyAsync(() -> {
//            int j = 10;
//            System.out.println(Thread.currentThread().getName());
//            try {
//                Thread.sleep(500);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//
//            return j / 5;
//        }, poolExecutor).thenRunAsync(() ->
//        {
//            System.out.println("我是什么线程" + Thread.currentThread().getName());
//        }, poolExecutor);

//        // 能接受上一个处理的参数没有返回值
//        CompletableFuture.supplyAsync(() -> {
//            int i = 10;
//            System.out.println(Thread.currentThread().getName());
//
//            return i / 5;
//        }, poolExecutor).thenAcceptAsync(res -> System.out.println(res), poolExecutor);
//
//        // 能接受上一个处理的参数并且有返回值
//        CompletableFuture<String> thenApplyAsync = CompletableFuture.supplyAsync(() -> {
//            int i = 10;
//            System.out.println(Thread.currentThread().getName());
//
//            return i / 5;
//        }, poolExecutor).thenApplyAsync(res -> "我可以有自己的返回值", poolExecutor);

//        两个CompletableFuture都需要完成
//        thenCombine: 组合两个future,获取两个future的返回结果，并返回当前任务的返回值
//        thenAcceptBoth:组合两个future,获取两个future任务的返回结果，然后处理任务，没有返回值。
//        runAfterBoth: 组合两个future,不需要获取future 的结果，只需两个future处理完任务后，处理该任务。
//        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
//            int i = 5;
//            System.out.println("第一个异步任务");
//            return i / 2;
//        }, poolExecutor);
//
//        CompletableFuture<Integer> future02 = CompletableFuture.supplyAsync(() -> {
//            int i = 6;
//            System.out.println("第二个异步任务");
//            return i / 2;
//        }, poolExecutor);
//
//        future01.runAfterBothAsync(future02,()->{
//            System.out.println("获取不到前面两个任务的结果，没有返回值");
//        },poolExecutor);
//
//        future01.thenAcceptBothAsync(future02,(res1, res2)->{
//            System.out.println("可以获取到前面两个任务的结果，没有返回值");
//        },poolExecutor);
//
//        future01.thenCombineAsync(future02,(res1, res2)->{
//            System.out.println("可以获取到前面两个任务的结果，有返回值");
//            return "我有自己的返回值";
//        },poolExecutor);

//        < -------------------------------------------------- >
//        applyToEither：两个任务有一个执行完成，获取它的返回值，处理任务并有新的返回值。
//        acceptEither：两个任务有一个执行完成，获取它的返回值，处理任务，没有新的返回值。
//        runAfterEither：两个任务有一个执行完成，不需要获取 future 的结果，处理任务，也没有返回值。
//        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
//            int i = 5;
//
//            try {
//                Thread.sleep(500);
//                System.out.println("第一个异步任务");
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            return i / 2;
//        }, poolExecutor);
//
//        CompletableFuture<Integer> future02 = CompletableFuture.supplyAsync(() -> {
//            int i = 6;
//            System.out.println("第二个异步任务");
//            return i / 2;
//        }, poolExecutor);
//
//        future01.runAfterEitherAsync(future02,() -> {
//            System.out.println("前面两个有一个完成就行");
//        },poolExecutor);

//        < -------------------------------------------------- >
//        allOf：等待所有任务完成
//        anyOf：只要有一个任务完成
//        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
//            int i = 5;
//
//            try {
//                Thread.sleep(500);
//                System.out.println("第一个异步任务");
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            return i / 2;
//        }, poolExecutor);
//
//        CompletableFuture<Integer> future02 = CompletableFuture.supplyAsync(() -> {
//            int i = 6;
//            System.out.println("第二个异步任务");
//            return i / 2;
//        }, poolExecutor);
//
//        CompletableFuture<Void> allOf = CompletableFuture.allOf(future01, future02);
//
//        // 等待两个任务都执行完成
//        allOf.get();
//        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future01, future02);
//
//
//        // 等待两个任务其中一个执行完成，返回的是成功的任务的返回值
//        Object o = anyOf.get();
//        Thread.sleep(500);
//        System.out.println("全部任务都完了");
    }

}
